package com.delete.action;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.commons.lang3.StringUtils;

import com.delete.executors.ExeParameter;
import com.delete.executors.ExecutorFactory;
import com.delete.executors.MExecutor;
import com.delete.sql.SqlCreate;
import com.delete.sql.SqlCreateForPager;
import com.kevin.enums.DBType;
import com.kevin.enums.action.InsertOp;
import com.kevin.enums.transaction.TransactionIsolationLevel;
import com.kevin.exceptions.ExceptionFactory;
import com.kevin.sql.SqlCompatible;
import com.kevin.sql.SqlFormat;
import com.kevin.table.MDataCell;
import com.kevin.table.MDataRow;
import com.kevin.table.MDataTable;

public class MAction implements AutoCloseable {

	/**
	 * 存储数据结构的行
	 */
	private MDataRow structRow;
	private SqlCreate sqlCreate;
	private MExecutor executor;

	/**
	 * 表名
	 */
	private String tableName;
	private boolean hasClosed = false;

	/**
	 * 原始传进来的表名/视图名，未经过[多数据库转换处理]格式化。
	 */
	private String sourceTableName;

	public MAction(Object tableNames) {
		init(tableNames, true, ExecutorFactory.getDefaultExecutorName());
	}

	public MAction(Object tableNames, String executorName) {
		init(tableNames, true, executorName);
	}

	/**
	 * 初始化
	 * 
	 * @param tableObj
	 * @param executorName
	 * @throws SQLException
	 */
	private void init(Object tableObj, boolean resetState, String executorName) {
		// 如果传入的是语句，给加个别名当做视图处理
		tableObj = SqlCreate.sqlToViewSql(tableObj);
		// 如果传入的是row,对结构行进行赋值处理
		if (tableObj instanceof MDataRow) {
			structRow = (MDataRow) tableObj;
		} // 在这里认为传入的tableObj 是string
		else {
			structRow = new MDataRow();
			// 这里的tableObj 可能是语句也可能是 名字
			structRow.setTableName(SqlFormat.notKeyword(tableObj.toString()));
		}

		// 将语句或者表名存储一下
		sourceTableName = structRow.getTableName();

		// 尝试通过表名获取执行器名称 executorName.TableName 形式
		String exeName = TableSchemaHandler.getExecutorName(tableObj);
		// 如果调用的时候没有传递executorName 属性，则用新获取的代替，否则以传入的为准
		if (executorName == ExecutorFactory.getDefaultExecutorName() && StringUtils.isNotEmpty(exeName)) {
			executorName = exeName;
		}
		// 初始化构造行的执行器名称
		if (StringUtils.isNotEmpty(executorName)) {
			//structRow.setExecutorName(executorName);
		}

		// 给执行器赋值
		if (executor == null) {
			//executor = ExecutorFactory.getExecutor(structRow.getExecutorName());
		}

		// sourceTableName 里面存储的是表明或语句，如果是语句需要格式化一下
		tableName = SqlCompatible.Format(sourceTableName, executor.getDbType());
		// 通过执行器匹配上边已经处理好的表名，如果匹配不到会返回传进去的值
		tableName = TableSchemaHandler.getMapTableName(executor.getExecutorName(), tableName);// 处理数据库映射兼容。

		// 如果没有任何的单元格需要加载表结构
		if (structRow.size() == 0) {
			structRow = TableSchemaHandler.fillTableSchema(structRow, executor, tableName, sourceTableName);
		} // 如果本来就存在，根据需要是否重置状态
		else if (resetState) {
			structRow.resetState(0);
		}

		if (sqlCreate == null)
			sqlCreate = new SqlCreate(this);
	}

	public MDataTable select() {
		return select(0, 0, null);
	}

	public MDataTable select(Object where) {
		return select(0, 0, where);
	}

	public MDataTable select(int topN, Object where) {
		return select(0, topN, where);
	}

	public MDataTable select(int pageIndex, int pageSize) {
		return select(pageIndex, pageSize, null);
	}

	/**
	 * 查询方法
	 * 
	 * @param pageIndex
	 *            页码
	 * @param pageSize
	 *            每页数量
	 * @param where
	 *            查询条件
	 * @return
	 * @throws Exception
	 */
	public MDataTable select(Integer pageIndex, Integer pageSize, Object where) {
		Integer rowCount = 0;
		String primaryKey = SqlFormat.keyword(structRow.getColumns().getFirstPrimary().getColumnName(),
				executor.getDbType());// 主键列名。
		MDataTable table = new MDataTable(tableName.contains("(") ? "SysDefaultCustomTable" : tableName);
		table.loadRowStruct(structRow);
		String whereSql = StringUtils.EMPTY;
		boolean bypager = pageIndex > 0 && pageSize > 0;
		if (bypager) {
			rowCount = count(whereSql);
		}
		if (sqlCreate != null) {
			whereSql = sqlCreate.formatWhere(where);
		} else {
			whereSql = SqlFormat.compatible(where, executor.getDbType(), true);
		}
		String sql = SqlCreateForPager.getSql(executor.getDbType(), pageIndex, pageSize, whereSql,
				SqlFormat.keyword(tableName, executor.getDbType()), rowCount, sqlCreate.getColumnsSql(), primaryKey,
				structRow.getPrimaryCell().getCellstruct().isAutoIncrement());
		ResultSet sdResult = executor.query(sql);
		table.loadData(sdResult);
		table.setTotal(rowCount);
		return table;
	}

	/**
	 * 更新方法
	 * 
	 * @param where
	 * @return
	 */
	public int update(Object where) {
		int affectedCount = 0;
		if (isClosed())
			return affectedCount;
		if (where == null || String.valueOf(where).equals(StringUtils.EMPTY)) {
			where = sqlCreate.getPrimaryWhere();
		}
		switch (executor.getDbType()) {
		case TXT:
		case XML:
			break;

		default:
			String sql = sqlCreate.getUpdateSql(where);
			affectedCount = executor.update(sql);
			break;
		}
		return affectedCount;
	}

	/**
	 * 插入方法
	 * 
	 * @param where
	 * @return
	 */
	public int insert(InsertOp option) {
		int affectedCount = 0;
		if (isClosed())
			return affectedCount;
		switch (executor.getDbType()) {
		case TXT:
		case XML:
			break;

		default:
			String sql = sqlCreate.buildInsertSql();
			affectedCount = executor.update(sql);
			if (option.equals(InsertOp.ID)) {
				if (getStructRow().getPrimaryCell().isEmpty()) {
					ResultSet result = executor.query(sqlCreate.getMaxID());
					try {
						if (result.next()) {
							getStructRow().getPrimaryCell().setValue(result.getInt(1));
						}
					} catch (SQLException e) {
						e.printStackTrace();
						throw ExceptionFactory.Exception(e);
					}
				}
			}
			break;
		}
		return affectedCount;
	}

	
	public int batchInsert(MDataTable table,InsertOp option){
		MDataRow row = null;
		String sql = StringUtils.EMPTY;
		int affectedCount = 0;
		int oneCount = 0;
		for (int i = 0; i < table.getRows().size(); i++) {
			row = table.getRows().get(i);
			if(i == 0){
				sql = sqlCreate.buildInsertSql(row);
				oneCount = executor.parametersSize();
			}else{
				sqlCreate.buildInsertSql(row);
			}
		}
		affectedCount = executor.updateBatch(sql,oneCount);	
		return affectedCount;	
	}
	
	/**
	 * 删除方法
	 * 
	 * @param where
	 * @return
	 */
	public boolean delete(Object where) {
		if (isClosed())
			return false;
		int result = 0;
		if (where == null || String.valueOf(where).equals(StringUtils.EMPTY)) {
			where = sqlCreate.getPrimaryWhere();
		}
		switch (executor.getDbType()) {
		case TXT:
		case XML:
			break;

		default:
			String sql = sqlCreate.getDeleteSql(where);
			result = executor.update(sql);
			break;
		}
		return result > 0;
	}

	/**
	 * 获取数量
	 * 
	 * @param where
	 * @return
	 */
	public int count(Object where) {
		int count = 0;
		if (isClosed())
			return count;
		switch (executor.getDbType()) {
		case TXT:
		case XML:
			break;

		default:
			String countSql = sqlCreate.getCountSql(where);
			System.out.println(countSql);
			ResultSet result = executor.query(countSql);
			try {
				if (result.next()) {
					count = result.getInt(1);
				}
			} catch (SQLException e) {
				e.printStackTrace();
				throw ExceptionFactory.Exception(e);
			}
			break;
		}
		return count;
	}

	public void beginTransation() {
		executor.beginTransation(null);
	}

	public void beginTransation(TransactionIsolationLevel level) {
		executor.beginTransation(level);
	}

	public void endTransation() {
		executor.endTransation();
	}

	public String getTableName() {
		return tableName;
	}

	public DBType getDBType() {
		return executor.getDbType();
	}

	public MDataRow getStructRow() {
		return structRow;
	}

	public MExecutor getExecutor() {
		return executor;
	}

	/*
	 * 释放资源 (non-Javadoc)
	 * 
	 * @see java.lang.AutoCloseable#close()
	 */
	@Override
	public void close() throws Exception {
		hasClosed = true;
		if (executor != null) {
			executor.close();
			executor = null;
			if (sqlCreate != null) {
				sqlCreate = null;
			}
		}

	}

	/**
	 * 资源已经被释放，不能再被使用
	 * 
	 * @return
	 */
	public boolean isClosed() {
		if (hasClosed || structRow.getColumns().size() == 0) {
			return true;
		}
		return false;
	}

	/**
	 * 对当前对象字段进行赋值操作
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	public MAction set(Object key, Object value) {
		return set(key, value, -1);
	}

	/**
	 * 对当前对象字段进行赋值操作
	 * 
	 * @param key
	 * @param value
	 * @param state 小于零，系统自动判断状态
	 * @return
	 */
	public MAction set(Object key, Object value, int state) {
		MDataCell cell = structRow.get(key);
		if (cell != null) {
			cell.setValue(value);
			if (state >= 0 && state < 3) {
				cell.setState(state);
			}
		} else {
			throw ExceptionFactory.Exception(new Exception("the cell for value is not exist!"));
		}
		return this;
	}

	/**
	 * 参数化查询参数设定
	 * 
	 * @param param
	 * @return
	 */
	public MAction setParam(ExeParameter param) {
		executor.addParameters(param);
		return this;
	}

	/**
	 * 获取设定的值
	 * 
	 * @param key
	 * @param t
	 * @return
	 */
	public <T> T get(Object key, Class<T> t) {
		return structRow.get(key, t);
	}
}
